
# 用于分类的线性模型
'''
线性模型在分类问题中的应用，特别是二分类，可以通过以下简化的解释来理解：

1. 预测公式：
   - 类似于线性回归，二分类线性模型使用公式 \( \hat{y} = w[0] \cdot x[0] + w[1] \cdot x[1] + \ldots + w[p] \cdot x[p] + b \) 来计算预测值 \( \hat{y} \)。
   - 不同的是，这个预测值用于确定分类的阈值（通常是0），如果 \( \hat{y} > 0 \) 则预测为正类（+1），如果 \( \hat{y} < 0 \) 则预测为负类（-1）。

2. 决策边界：
   - 对于分类模型，决策边界是由输入特征的线性组合定义的，这个边界将不同的类别分开。
   在二维空间中，这可以是一条直线；在三维空间中，这是一个平面；在更高维空间中，则是超平面。

3. 算法差异：
   - 学习线性模型的算法主要区别在于它们如何衡量模型对训练数据的拟合程度（损失函数）以及是否使用正则化，如果使用，是哪种类型的正则化。
   - 由于技术限制，不可能找到一个完美的模型，使得误分类数量最少，因此损失函数的选择对于实际应用来说并不是最关键的。

总结来说，线性模型在分类问题中通过设置阈值来预测类别，并且算法的不同主要体现在损失函数和正则化方法的选择上。

'''
import mglearn
from matplotlib import pyplot as plt
from sklearn.model_selection import train_test_split

'''
两种常见的线性分类算法是：
1. Logistic回归：虽然名字中有“回归”，但它是一种分类算法，用于二分类问题，不要与线性回归混淆。在`linear_model.LogisticRegression`中实现。
2. 线性SVM：即线性支持向量机，也是一种用于分类的线性模型，在`svm.LinearSVC`中实现。
这两种模型都可以用来处理分类问题，并且可以应用于数据集（如forge数据集）来可视化它们的决策边界。

'''

from sklearn.linear_model import LogisticRegression
from sklearn.svm import LinearSVC
X,y = mglearn.datasets.make_forge()
# 函数用于创建图形(figure)和子图(axes)
# nrows=1：指定图形中子图的行数为1。
# ncols=2：指定图形中子图的列数为2，这意味着将创建一个1行2列的子图布局。
# figsize=(10,3)：设置整个图形的大小为宽10英寸、高3英寸。
fig,axes = plt.subplots(nrows=1,ncols=2,figsize=(10,3))
for model,ax in zip([LinearSVC(),LogisticRegression()],axes):
 clf = model.fit(X,y)
 # 用于在二维空间中绘制分类器的决策边界
 mglearn.plots.plot_2d_separator(clf,X,fill=False,eps=0.5,ax=ax,alpha=.7)
 mglearn.discrete_scatter(X[:,0],X[:,1],y=y,ax=ax)
 ax.set_title(f"{clf.__class__.__name__}")
 ax.set_xlabel("Feature 0")
 ax.set_ylabel("Feature 1")
axes[0].legend()
# plt.show()

'''
 两个模型的决策边界相似，但都错了两个点。它们都用L2正则化，默认情况下，
 参数C控制正则化强度，C值大表示正则化弱，模型更贴近训练数据；
 C值小表示正则化强，模型更倾向于让系数接近0。
 C值小时，模型更注重适应大多数数据点；
 C值大时，更注重每个数据点的正确分类。
 线性分类模型在低维空间中决策边界受限，而在高维空间中更强大，需要避免过拟合。

'''

# 我们在乳腺癌数据集上详细分析 LogisticRegression
from sklearn.datasets import load_breast_cancer
cancer = load_breast_cancer()
X_train,X_test,y_train,y_test = train_test_split(cancer.data,cancer.target,stratify=cancer.target,random_state=42)
logreg = LogisticRegression().fit(X_train,y_train)
print("Training set score: {:.2f}".format(logreg.score(X_train,y_train)))
print("Test set score: {:.2f}".format(logreg.score(X_test,y_test)))
# Training set score: 0.96
# Test set score: 0.95

# C=1时，模型在训练集和测试集上表现都很好，精度都达到了95%。但由于两者性能太接近，这可能意味着模型欠拟合。
# 为了得到一个更灵活的模型，我们可以尝试增大C值。
logreg100 = LogisticRegression(C=100).fit(X_train, y_train)
print("Training set score: {:.3f}".format(logreg100.score(X_train, y_train)))
print("Test set score: {:.3f}".format(logreg100.score(X_test, y_test)))
# Training set score: 0.944
# Test set score: 0.965

# 我们还可以研究使用正则化更强的模型时会发生什么。设置 C=0.01
logreg001 = LogisticRegression(C=0.01).fit(X_train, y_train)
print("Training set score: {:.3f}".format(logreg001.score(X_train, y_train)))
print("Test set score: {:.3f}".format(logreg001.score(X_test, y_test)))
# Training set score: 0.934
# Test set score: 0.930

# 最后，来看一下正则化参数 C 取三个不同的值时模型学到的系数
plt.plot(logreg.coef_.T, 'o', label="C=1")
plt.plot(logreg100.coef_.T, '^', label="C=100")
plt.plot(logreg001.coef_.T, 'v', label="C=0.001")
plt.xticks(range(cancer.data.shape[1]), cancer.feature_names, rotation=90)
plt.hlines(0, 0, cancer.data.shape[1])
plt.ylim(-5, 5)
plt.xlabel("Coefficient index")
plt.ylabel("Coefficient magnitude")
plt.legend()
# plt.show()


'''

二分类线性模型和回归线性模型在很多方面相似，主要区别在于正则化的强度，这由penalty参数（惩罚系数）控制。
这个参数不仅影响模型的正则化程度，还决定了模型是使用所有特征还是仅选择其中一部分特征。
简单来说，penalty参数平衡了模型的复杂度和拟合度，影响特征的选择。
'''


# 用于多分类的线性模型
'''

这段文字解释了如何将二分类模型扩展到多分类问题，特别是使用“一对其余”（one-vs.-rest）方法：

1. 一对其余方法：
   - 许多线性分类模型原本只适用于二分类问题。要处理多分类问题，可以采用“一对其余”方法，即对每个类别训练一个二分类模型，将该类别与其他所有类别区分开来。
2. 模型数量：
   - 在“一对其余”方法中，会训练与类别数量一样多的二分类模型。每个模型负责区分一个类别和所有其他类别。
3. 预测过程：
   - 在测试阶段，对每个测试点运行所有二分类模型，然后选择分数最高的模型对应的类别作为预测结果。
4. 系数和截距：
   - 每个类别都有一个对应的系数向量（w）和一个截距（b），用于计算分类置信度。
5. 预测方程：
   - 使用方程 w[0] * x[0] + w[1] * x[1] + … + w[p] * x[p] + b 来计算每个类别的置信度，最大值对应的类别即为预测类别。
6. Logistic回归的多分类：
   - 尽管多分类Logistic回归背后的数学与“一对其余”方法有所不同，但它也是为每个类别训练一个模型，使用相同的预测方法。

总结来说，“一对其余”方法通过为每个类别训练一个二分类模型，将二分类算法扩展到多分类问题，通过比较所有模型的分数来确定最终的预测类别。

'''

'''
这段文字总结了线性模型的优缺点和参数调整：

1. 参数：
   - 正则化参数（alpha或C）控制模型的复杂度，较大的alpha值或较小的C值意味着更简单的模型。
   - 参数需要在对数尺度上进行调整。
   - 选择L1或L2正则化取决于是否只有少数特征重要，L1正则化有助于特征选择和模型解释。

2. 优点：
   - 训练和预测速度快，适合大型数据集和稀疏数据。
   - 可使用`solver='sag'`选项提高LogisticRegression和Ridge模型在大数据集上的性能。
   - SGDClassifier和SGDRegressor提供了更强的可扩展性。
   - 预测过程相对容易理解。

3. 缺点：
   - 在特征高度相关的情况下，系数的解释可能变得困难。
   - 当特征数量超过样本数量时，模型表现好，但在低维空间中，其他模型可能有更好的泛化性能。

总的来说，线性模型因其速度快和可扩展性而被广泛使用，尤其是在大规模数据集上。然而，它们在解释性和泛化能力上可能不如其他模型，
特别是在特征空间维度较低时。

'''
